<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>DllCall</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link href="../css/default.css" rel="stylesheet" type="text/css">
</head>
<body>

<h1>DllCall()</h1>

<p>调用 DLL 文件中的函数, 例如标准的 Windows API 函数.</p>

<pre class="Syntax">Result := DllCall(&quot;[DllFile\]Function&quot; [, Type1, Arg1, Type2, Arg2, &quot;Cdecl ReturnType&quot;])</pre>
<h3>参数</h3>
<table class="info">
  <tr>
    <td width="15%">Result</td>
    <td width="85%">DllCall 返回调用函数返回的实际值. 如果函数没有返回值, 那么结果为一个未定义整数. 如果函数在调用时发生 <a href="#error">错误</a>, 那么返回值为空 (一个空字符串).</td>
  </tr>
  <tr>
    <td>[DllFile\]Function</td>
    <td><p>DLL 或 EXE 文件的名字后面跟着一个反斜线和函数名. 例如: "MyDLL\MyFunction" (省略时文件扩展名默认为 ".dll"). 如果未指定绝对路径, 则假定 <em>DllFile</em> 在系统的 PATH 变量指定的路径或 <a href="../Variables.htm#WorkingDir">A_WorkingDir</a> 中.</p>
      <p>调用 User32.dll, Kernel32.dll, ComCtl32.dll, 或 Gdi32.dll 中的函数时可以省略 <em><a name="std"></a>DllFile</em>. 例如, "User32\IsWindowVisible" 和 "IsWindowVisible" 得到相同的结果. 对于这些标准的 DLL, 一些 API 函数含有的字母 "A" 后缀可以省略. 例如, "MessageBox" 等同于 "MessageBoxA".</p>
      <p>当 <em>重复</em> 调用 DLL 时通过 <a href="#load">预先装载此 DLL 文件</a> 可以显著改善执行效率.</p>
    <p>在 1.0.46.08 以上版本中, 此参数也可以是表示需调用函数的内存地址的整数. 如 <a href="#COM">COM</a> 和 <a href="RegisterCallback.htm">RegisterCallback()</a> 提供的地址.</p></td>
  </tr>
  <tr>
    <td>Type1, Arg1</td>
    <td>这样的每对数据, 表示需传递给函数的单个参数. 参数的个数没有限制. 关于 <em>Type</em>, 参见下面的 <a href="#types">类型表</a>. 关于 <em>Arg</em>, 指定传递给函数的值.</td>
  </tr>
  <tr>
    <td>Cdecl ReturnType</td>
    <td><p>通常省略 <a name="cdecl"></a>单词 <em>Cdecl</em> 因为大多数函数使用标准调用约定而不是 "C" 调用约定 (像 wsprintf 这样接受可变数目参数的函数在这点上是个例外). 如果您省略了 Cdecl 但调用时产生了 <a href="#An">ErrorLevel A<strong>n</strong></a> -- 这里 <strong>n</strong> 是您传递的参数的总大小 -- 此时可能需要加上 <em>Cdecl</em>.</p>
      <p>如果使用了, 那么单词 <em>Cdecl</em> 应该在返回值类型前列出 (如果有的话). 在单词间使用空格或 Tab 分隔. 例如: "Cdecl Str"</p>
      <p><span class="ver">[AHK_L 53+]:</span> 因为在 64 位代码中不使用 "C" 调用约定, 所以在 AutoHotkey_L 的 x64 版本中可以指定 <i>Cdecl</i> 但没有效果.</p>
      <p><em>ReturnType</em>: 如果函数返回一个 32 位的有符号整型 (Int), BOOL 或无返回值, <em>ReturnType</em> 可以省略. 否则需要指定下面 <a href="#types">类型表</a> 中参数类型的其中一个. 还支持 <a href="#asterisk">星号后缀</a>.</p>    </td>
  </tr>
</table>

<h3 id="types">参数和返回值类型</h3>
<table class="info">
<tr>
<td>Str</td>
<td><p><a name="str"></a>如 "Blue" 或 MyVar 这样的字符串型. 如果被调用函数修改了字符串并且此参数是个裸变量, 那么其内容将被更新. 例如, 后面的调用将把 <em>MyVar</em> 的内容转换成大写: <code>DllCall("CharUpper", "Str", <i>MyVar</i>)</code></p>
  <p>然而, 如果函数需要保存超过变量当前容量的字符串, 在调用前必须确保此变量的容量足够大. 这可以通过调用 <a href="VarSetCapacity.htm">VarSetCapacity(<em>MyVar</em>, 123)</a> 来实现, 这里 123 是为 <em>MyVar</em> 保留的容量.</p>
  <p><em>Str</em> 参数不能是计算结果为数字 (例如 i+1) 的 <a href="../Variables.htm#Expressions">表达式</a>. 如果这样, 不会调用函数并设置 ErrorLevel 的值为 -2.</p>
  <p>支持 <a href="#asterisk">asterisk variable</a> "Str*" 但极少使用. 它可以用在期望如 "char **" 或 "LPSTR *" 类型参数的函数中.</p>
  <p>注意: 传递字符串给函数时, 应该知道函数期望什么 <a href="../Compat.htm#DllCall"><i>类型</i> 的字符串</a>.</p></td>
</tr>
<tr>
  <td><a name="astr"></a><a name="wstr"></a>AStr<br>WStr</td>
  <td><span class="ver">[AHK_L 42+]:</span> <b>A</b>NSI 或 Unicode (<b>宽</b> 字符) 字符串型. 参见 <a href="../Compat.htm#DllCall">脚本兼容性</a> 了解等同的 Win32 类型和其他细节.</td>
</tr>
<tr>
  <td>Int64</td>
  <td>64 位整型, 其范围为 -9223372036854775808 (-0x8000000000000000) 到 9223372036854775807 (0x7FFFFFFFFFFFFFFF).</td>
</tr>
<tr>
  <td>Int</td>
  <td id="Int"><p>32 位整型 (最常用的整数类型), 其范围为 -2147483648 (-0x80000000) 到 2147483647 (0x7FFFFFFF). Int 有时也写成 "Long".</p>
    <p>整型也用于描述 BOOL 类型的参数 (一个 BOOL 值应该为 1 或 0).</p>
    <p><a href="#unsigned">无符号</a> 整型 (UInt) 也是频繁使用的类型, 例如用于 DWORD 和 HWND.</p></td>
</tr>
<tr>
  <td>Short</td>
  <td>16位整型, 其范围为 -32768 (-0x8000) 到 32767 (0x7FFF). <a href="#unsigned">无符号</a> 短整型 (UShort) 可用于函数参数的 WORD 类型.</td>
</tr>
<tr>
  <td>Char</td>
  <td>8 位整型, 其范围为 -128 (-0x80) 到 127 (0x7F). <a href="#unsigned">无符号</a> 字符型 (UChar) 可用于函数参数的 BYTE 类型.</td>
</tr>
<tr>
  <td>Float</td>
  <td>32 位浮点数, 具有 6 位精确度. </td>
</tr>
<tr>
  <td>Double</td>
  <td>64 位浮点数, 具有 15 位精确度. </td>
</tr>
<tr>
  <td>Ptr</td>
  <td id="ptr"><p><span class="ver">[AHK_L 42+]:</span> <a href="../Variables.htm#PtrSize">指针大小的</a> 整型. <i>Ptr</i> 应该用于数组或结构中的指针 (例如 RECT*) 和几乎所有句柄 (例如 HWND, HBRUSH 和 HBITMAP). 它通常不应该与指向简单值的指针例如 LPDWORD 或 int* 一起使用; 在这样情况下合适的 DllCall 类型应该带有 * 或 P 后缀 (见下面).</p>
  <p><i>Ptr</i> 也可以和 * 或 P 后缀一起使用; 它应该和通过 LPVOID* 或类似类型输出指针的函数一起使用.</p>
  <p><i>UPtr</i> 也是有效的, 但仅适用于 32 位版本中的无符号整型因为 AutoHotkey 不支持无符号的 64 位整型.</p>
  <p>如果需要和旧版本的 AutoHotkey 兼容, 使用如下所示的变量类型:</p>
  <pre>Ptr := A_PtrSize ? "Ptr" : "UInt" <em>; If A_PtrSize is not defined, use UInt instead.</em>
DllCall("DeleteFile", Ptr, &amp;filename) <em>; Omit the quote marks around Ptr.</em></pre>
  <p>注意: 要传递 <strong>NULL</strong> 句柄或指针, 请传递整数 0.</p></td>
</tr>
<tr>
  <td>* or P<br>
    (后缀) </td>
  <td id="asterisk"><p>在上述任一类型后附加一个星号 (星号前可以含有空格) 表示传递参数的地址而不是参数的值 (被调用函数必须接受地址). 由于这样的参数的值可能被函数修改, 每当不受保护的变量作为参数传递时, 变量的内容都会被更新. 例如, 后面的调用把 MyVar 的地址传给 MyFunction 但也会更新 MyVar 的内容来反映 MyFunction 对其做出的修改: DllCall("MyDll\MyFunction", "Int*", MyVar)</p>
    <p>一般说来, 星号可用于函数中以 "LP" 开始的参数类型或返回值类型. 最常见的例子是 LPDWORD, 这是指向变量类型 DWORD 的指针类型. 因为 DWORD 是无符号 32 位整型, 所以用 "UInt*" 或 "UintP" 来表示 LPDWORD 的类型. 星号不应该用于字符串类型如 LPTSTR, 指向结构的指针如 LPRECT, 或数组; 对于这些, 根据您需要传递的是变量还是其地址应该使用 <a href="#str">"Str"</a> 或 "Ptr".</p>
    <p>注意: "Char*" 与 <a href="#str">"Str"</a> 的类型是不同的因为 "Char*" 传递 8 位数的地址, 而 <a href="#str">"Str"</a> 传递一序列字符的地址. 同样地, "UInt*" 传递 32 位数的地址, 所以如果函数期望大于 32 位的结构或值的数组时不应该使用. 并且, 在函数将保存数字时不需要对星号变量调用 <a href="VarSetCapacity.htm">VarSetCapacity</a> 来扩大其容量.</p></td>
</tr>
<tr>
  <td>U (前缀) </td>
  <td><p><a name="unsigned"></a>在上述任一整型前加上字母 U 表示无符号整型 (UInt64, UInt, UShort, 和 UChar). 严格说来, 这仅对于返回值或 <a href="#asterisk">星号变量</a> 才是必要的因为它不影响传递值的参数是无符号的还是有符号的 (除了 Int64).</p>
    <p>如果在无符号参数中指定负整数, 那么它会被转换到无符号范围内. 例如, 把 -1 作为 UInt 类型, 它会被转换成 0xFFFFFFFF.</p>
    <p>不支持由函数产生的 <em>无符号</em> 64 位整型. 因此, 要让大于或等于 0x8000000000000000 的数字起作用, 忽略 U 前缀并且把任何从函数接收到的负值转换成很大的正数. 例如, 如果设计返回值为 UInt64 类型的函数当函数返回 Int64 类型的 -1 值时实际返回值是 0xFFFFFFFFFFFFFFFF.</p></td>
</tr>
</TABLE>
<p><strong>注意</strong>: 当指定不包含空格或星号的参数类型或返回值类型时, 包围的引号可以省略. 例如, 可以使用 str 代替 "Str" 而 CDecl 代替 "CDecl". 此外, 用字母 P 代替星号这样也可以省略引号. 例如: UIntP.</p>

<h3 id="error">返回值</h3>
<p><a href="../misc/ErrorLevel.htm">ErrorLevel</a> 会被设置为下列值的其中一个来表示调用成功或失败.</p>
<p><strong>0</strong>: 成功.</p>
<p><strong>-1</strong> (负 1): <em>[DllFile\]Function</em> 参数是一个浮点数. 要求参数为字符串或正整数.</p>
<p><strong>-2</strong>: <a href="#types">返回值类型</a> 或指定的 <a href="#types">参数类型</a> 中某一个无效. 此错误也可能由传递一个计算结果为数字的 <a href="../Variables.htm#Expressions">表达式</a> 给一个字符串 (<a href="#str">str) </a> 参数引起.</p>
<p><strong>-3</strong>: 无法访问指定的 <em>DllFile</em>. 如果没有明确指明 <em>DllFile</em> 的路径, 则文件必须在系统的 PATH 变量路径或 <a href="../Variables.htm#WorkingDir">A_WorkingDir</a> 中. 此错误也可能由用户缺少访问此文件的权限引起.</p>
<p><strong>-4</strong>: 在 DLL 中没有找到指定的函数.</p>
<p><strong>N</strong> (任意正数): 调用了函数但异常终止了, 致命异常号为 <strong>N</strong> (例如, 0xC0000005 表示 "访问违例"). 此时函数返回一个空值 (空字符串), 但所有 <a href="#asterisk">星号变量</a> 仍会被更新. 致命异常的一个例子是间接引用了无效的指针例如 NULL. 因为 <a href="#cdecl">Cdecl</a> 函数决不会产生下一段中的 <em>"An"</em> 错误, 所以当传递给它的参数太少时可能会产生异常.</p>
<p><strong><a name="An"></a>An</strong> (字母 A 后面跟着一个整数 <strong>n</strong>): 表示调用了函数但传递给它的参数太多或太少了. "<strong>n</strong>" 是is the number of bytes by which the argument list was incorrect. 如果 <strong>n</strong> 为正数, 表示传递的参数过多 (或参数太大), 或函数调用要求 <a href="#cdecl">CDecl</a> 类型的参数. 如果 <strong>n</strong> 为负数, 表示传递的参数过少. 应该改正这种情况来确保函数的可靠运行. 此错误的出现也可能表示出现了异常, 此时函数返回空字符串. 请注意由于 x64 调用约定, 64 位版本不会设置 ErrorLevel 为 <b>An</b>.</p>

<h3 id="except">异常和 A_LastError</h3>
<p>尽管有内置的异常处理机制, 但仍有可能使用 DllCall 而让脚本崩溃. 当一个函数不直接产生异常而产生一些不适当的数据例如无效指针或没有结束符的字符串时, 这种情况可能发生. 这可能不是因为函数本身的错误而是脚本传递给它不适合的值例如一个无效指针或一个内存空间不足的 <a href="#str">"str</a>". 当脚本指定一个不适当的参数类型或返回值类型, 例如要求由函数生成的整数是一个 <a href="#asterisk">星号变量</a> 或 <a href="#str">str</a>, 这时它也可能崩溃.</p>
<p><a name="LastError"></a>内置变量 <strong>A_LastError</strong> 包含了操作系统 GetLastError() 函数返回的结果, 此函数会在调用函数后被立即执行 (对效率的影响不可知). A_LastError 是一个介于 0 和 4294967295 之间的数字 (通常表示为十进制而非十六进制). 像 <a href="../misc/ErrorLevel.htm">ErrorLevel</a> 一样, A_LastError 是一个与每个线程关联的设置; 即由其他 <a href="../misc/Threads.htm">线程</a> 产生的中断无法改变它的值. 不过, <a href="Run.htm#LastError">Run/RunWait</a> 也会设置 A_LastError 的值.</p>

<h3 id="load">性能</h3>
<p>当需要重复调用一个 DLL 时, 事先明确装载它可以显著提高执行效率 (<em>对于 <a href="#std">标准的 DLL</a> 文件如 User32 可以不需要, 因为它总是常驻的</em>). 这样的实现避免了 DllCall 每次内部调用 LoadLibrary 和 FreeLibrary 的需要. 例如:</p>
<pre>hModule := DllCall("<strong>LoadLibrary</strong>", "Str", "MyFunctions.dll")  <em>; 避免了 DllCall() 在循环中每次都装载库的需要.</em>
Loop, C:\My Documents\*.*, , 1
    result := DllCall("MyFunctions\BackupFile", "Str", A_LoopFileFullPath)
DllCall("<strong>FreeLibrary</strong>", "Ptr", hModule)  <em>; 为了释放内存, DLL 在使用后需要卸载.</em></pre>
<p>在高于 1.0.46.08 的版本中, 通过预先查找函数的地址甚至可以获得更快的性能. 例如:</p>
<pre><em>; 在后面的例子中, 如果 DLL 还没有装载, 使用 LoadLibrary 代替 GetModuleHandle.</em>
<strong>MulDivProc</strong> := DllCall("GetProcAddress", Ptr, DllCall("GetModuleHandle", Str, "<strong>kernel32</strong>"), AStr, "<strong>MulDiv</strong>")
循环 500
    DllCall(<strong>MulDivProc</strong>, Int, 3, Int, 4, Int, 3)</pre>
<p><span class="ver">[AHK_L 31+]:</span> 如果 DllCall 的首个参数是一个原义的字符串例如 <code>"MulDiv"</code> 并且包含了函数的 DLL 在脚本开始前已正常装载了, 此字符串会自动被解析为函数地址. 这个内置的最优化比上述演示的例子执行的更高效.</p>
<p>同时, 在脚本的任意位置添加 <a href="_NoEnv.htm">#NoEnv</a> 行可以改善 DllCall 的性能当使用了未引用的参数类型时 (例如 Int 与  "Int").</p>
<p>最后, 当传递一个字符串变量给不会改变它长度的函数时, 传递变量的 <a href="../Variables.htm#amp">地址</a> 可以提升性能 (例如 &amp;MyVar) 而不是作为 "<a href="#str">str</a>" (尤其是当字符串很长的时候). 后面的例子把字符串转换成大写: DllCall("CharUpper", <strong>Ptr</strong>, <em><strong>&amp;</strong>MyVar</em>)</p>

<h3 id="struct">结构体和数组</h3>
<p>结构体是内存中一系列连续的 <em>成员</em> (空间). 大多数成员变量类型是整型.</p>
<p>调用接受结构体地址 (或内存块数组) 的函数可以把结构体的原始二进制数据保存到普通变量中. 一般步骤如下:</p>
<p>1) 调用 <code><a href="VarSetCapacity.htm">VarSetCapacity</a>(MyStruct, 123, 0)</code> 确保目标变量足够大以便保存结构体数据. 把 123 替换为至少和结构体大小一样大的数字. 最后一个参数零是可选的; 它会初始化所有成员变量为二进制零, 这样通常可以避免在下一步中频繁调用 NumPut().</p>
<p>2) 如果目标函数需要初始化结构体, 调用 <code><a href="../Functions.htm#NumPut">NumPut</a>(123, MyStruct, 4, "UInt")</code> 来初始化任意一个成员为非零数据. 把 123 替换为需要向目标成员存入的整数 (或指定 <code>&amp;Var</code> 来存入变量的 <a href="../Variables.htm#amp">地址</a>). 把 4 替换为目标成员的偏移量 (关于 "偏移" 的描述请参见步骤 #4). 把 "UInt" 替换为合适的类型或当成员是指针或句柄时省略.</p>
<p>3) 调用目标函数, 把 MyStruct 的 <a href="../Variables.htm#amp">地址</a> 作为 UInt 类型 (或 Ptr 在 AHK_L 42+ 时) 的参数传递过去. 例如, <code>DllCall("MyDll\MyFunc", Ptr, <strong>&amp;</strong>MyStruct)</code>. 函数将检查和/或改变其中的某些成员变量.</p>
<p>4) 使用 <code>MyInteger := <a href="../Functions.htm#NumGet">NumGet</a>(MyStruct, 4, "UInt")</code> 从结构体中获取任何想要的成员变量. 把 4 替换为结构体中目标成员的偏移量. 首个成员变量的偏移量总为 0. 第二个成员的偏移量为 0 加上首个成员的大小 (一般为 4 字节). 后面成员的偏移量等于它前一个成员的偏移量加上前一个成员的大小. 大多数成员 -- 例如 DWORD, Int, 和 <a href="#Int">其他 32 位整型</a> -- 是 4 个字节的大小. 把 "UInt" 替换为合适的类型或当成员是指针或句柄时省略.</p>
<p>参见 <a href="#ExStruct">结构体示例</a> 了解实际用法.</p>
<h3 id="limits">已知限制</h3>
<p>当把一个 <a href="../Variables.htm#amp">变量的地址</a> (例如 &amp;MyVar) 传递给函数而此函数修改了变量内容的长度, 后面使用这个变量可能产生错误. 要解决此问题, 有后面几种方法: 1) 把 MyVar 作为 <a href="#str">"Str"</a> 参数而不是 Ptr/地址 传递; 2) 在 1.0.44.03+ 版本中, 在调用 DllCall 后使用 <a href="VarSetCapacity.htm#neg1">VarSetCapacity(MyVar, -1)</a> 更新变量的内部容量.</p>
<p>由函数保存到变量中的任何二进制零会隐藏这个零右边的所有数据; 即这样的数据无法被大多数命令和函数访问或修改. 但是这样的数据可以通过 <a href="../Variables.htm#amp">地址运算符</a> 和 <a href="../Functions.htm#NumPut">NumPut</a>/<a href="../Functions.htm#NumGet">NumGet</a> 操作, 和 DllCall 一样.</p>
<p>当一个字符串传递给一个返回此字符串地址的函数后, 此函数可能会出乎意料地返回一个地址不同内容相同的字符串. 例如在编程语言中调用 CharLower(CharUpper(MyVar)) 将把 <em>MyVar</em> 的内容转换成小写. 但当使用 DllCall() 进行相同操作时, 在后面的调用操作后 <em>MyVar</em> 将是小写的因为 CharLower 对一个内容与 <em>MyVar</em> 相同地址不同的临时字符串进行操作:</p>
<pre>MyVar = ABC
result := DllCall("CharLower", <strong><u>str</u></strong>, DllCall("CharUpper", Str, MyVar, <strong><u>Str</u></strong>), Str)</pre>
<p>要变通解决此问题, 把上面两个带下划线的 "Str" 修改成 Ptr. 这种情况说明了 CharUpper 的返回值为纯地址并作为整数类型传递给 CharLower.</p>
<p>处理字符串时可能遇到某些限制. 想了解详情, 参见 <a href="../Compat.htm#DllCall">脚本兼容性</a>.</p>
<h3 id="COM">VBScript, JScript, 和组件对象模型 (COM)</h3>
<p><span class="ver">[AHK_L 53+]:</span> 通过 <a href="ComObjCreate.htm">ComObjCreate</a>, <a href="ComObjGet.htm">ComObjGet</a> 或 <a href="ComObjActive.htm">ComObjActive</a> 可以原生支持实现了 <a href="http://msdn.microsoft.com/en-us/library/dd318520.aspx">IDispatch</a> 的 COM 对象. </p>
<p>VBScript 和 JScript 可以通过 <a href="http://www.autohotkey.net/%7Eeasycom/">Windows Scripting for AutoHotkey</a> 嵌入到脚本中, 这样也可以访问 COM.</p>
<p>同样, 通过 DllCall 可以直接使用 COM, 参考示例: <a href="http://www.autohotkey.com/wiki/index.php?title=COM_Wrappers">www.autohotkey.com/wiki/index.php?title=COM_Wrappers</a>.</p>

<h3>相关</h3>
<p><a href="../Compat.htm#DllCall">脚本兼容性</a>, <a href="PostMessage.htm">PostMessage</a>, <a href="OnMessage.htm">OnMessage()</a>, <a href="RegisterCallback.htm">RegisterCallback()</a>, <a href="Run.htm">Run</a>, <a href="VarSetCapacity.htm">VarSetCapacity</a>, <a href="../Functions.htm">函数</a>, <a href="SysGet.htm">SysGet</a>, <a href="http://msdn.microsoft.com/library/">MSDN Library</a></p>
<h3>示例</h3>
<pre class="NoIndent"><em>; 示例: Calls the Windows API function "MessageBox" and report which button the user presses.</em>

WhichButton := DllCall("MessageBox", "Int", "0", "Str", "Press Yes or No", "Str", "Title of box", "Int", 4) MsgBox You pressed button #%WhichButton%.</pre>

<pre class="NoIndent"><em>; 示例: Changes the desktop wallpaper to the specified bitmap (.bmp) file.</em>

DllCall("SystemParametersInfo", UInt, 0x14, UInt, 0, Str, <i>A_WinDir <strong>.</strong> "\winnt.bmp"</i>, UInt, 2)</pre>

<pre class="NoIndent"><em>; 示例: Calls the API function "IsWindowVisible" to find out if a Notepad window is visible.</em>

DetectHiddenWindows On if not DllCall("IsWindowVisible", "Ptr", WinExist("Untitled - Notepad")) <em>; WinExist() returns an HWND.</em>
 MsgBox The window is not visible.</pre>

<pre class="NoIndent"><em>; 示例: Calls the API's wsprintf() to pad the number 432 with leading zeros to make it 10 characters wide (0000000432).</em>

VarSetCapacity(ZeroPaddedNumber, 20) <em>; Ensure the variable is large enough to accept the new string.</em>
DllCall("wsprintf", "Str", ZeroPaddedNumber, "Str", "%010d", "Int", 432, "Cdecl") <em>; Requires the Cdecl calling convention.</em>
MsgBox %ZeroPaddedNumber%</pre>

<pre class="NoIndent"><a name="QPC"></a><em>; 示例: Demonstrates QueryPerformanceCounter(), which gives more precision than <a href="../Variables.htm#TickCount">A_TickCount's</a> 10ms.</em>

DllCall("QueryPerformanceCounter", "Int64*", CounterBefore) Sleep 1000 DllCall("QueryPerformanceCounter", "Int64*", CounterAfter) MsgBox % "Elapsed QPC time is " . CounterAfter - CounterBefore</pre>

<pre class="NoIndent"><em>; 示例: This is a hotkey that temporarily reduces the mouse cursor's speed, which facilitates precise positioning. ; Hold down the F1 key to slow down the cursor. Release it to return to original speed.</em>

F1:: SPI_GETMOUSESPEED = 0x70 SPI_SETMOUSESPEED = 0x71
<em>; Retrieve the current speed so that it can be restored later:</em>
<strong>DllCall</strong>("SystemParametersInfo", UInt, SPI_GETMOUSESPEED, UInt, 0, UIntP, OrigMouseSpeed, UInt, 0)
<em>; Now set the mouse to the slower speed specified in the next-to-last parameter (the range is 1-20, 10 is default):</em>
<strong>DllCall</strong>("SystemParametersInfo", UInt, SPI_SETMOUSESPEED, UInt, 0, Ptr, <strong>3</strong>, UInt, 0) KeyWait F1 <em>; This prevents keyboard auto-repeat from doing the DllCall repeatedly.</em>
return F1 up::<strong>DllCall</strong>("SystemParametersInfo", UInt, 0x71, UInt, 0, Ptr, OrigMouseSpeed, UInt, 0) <em>; Restore the original speed.</em></pre>

<pre class="NoIndent"><a name="GetChildHWND"></a><em>; 示例: When passed a window's Unique ID and the text or ClassNN of one of its controls, ; the following function returns the HWND (unique ID) of that control. ; v1.0.43.06+: This function has been superseded by the following command, which is more accurate.</em>

<a href="ControlGet.htm#Hwnd">ControlGet, OutputVar, Hwnd,, ClassNN, WinTitle</a></pre>

<pre class="NoIndent"><em>; 示例: Monitors the active window and display the position of its vertical scroll bar in its ; focused control (with real-time updates). This requires v1.0.43.06+ because it uses <a href="ControlGet.htm#Hwnd">ControlGet Hwnd</a></em>. #Persistent SetTimer, WatchScrollBar, 100 return WatchScrollBar: ActiveWindow := WinExist("A") if not ActiveWindow <em>; No active window.</em>
 return ControlGetFocus, FocusedControl, ahk_id %ActiveWindow% if not FocusedControl <em>; No focused control.</em>
 return
<em>; Display the vertical or horizontal scroll bar's position in a ToolTip:</em>
ControlGet, ChildHWND, Hwnd,, %FocusedControl%, ahk_id %ActiveWindow% ToolTip % <strong>DllCall</strong>("GetScrollPos", "Ptr", ChildHWND, "Int", 1) <em>; Last parameter is 1 for SB_VERT, 0 for SB_HORZ.</em>
return</pre>

<pre class="NoIndent"><a name="file"></a><em>; 示例: This is a working script that writes some text to a file then reads it back into memory (requires v1.0.34+). ; This method can be used to help performance in cases where multiple files are being read or written simultaneously.</em>

FileSelectFile, FileName, S16,, Create a new file: if FileName = return GENERIC_WRITE = 0x40000000 <em>; Open the file for writing rather than reading.</em>
CREATE_ALWAYS = 2 <em>; Create new file (overwriting any existing file).</em>
hFile := <strong>DllCall</strong>("CreateFile", Str, FileName, UInt, GENERIC_WRITE, UInt, 0, Ptr, 0, UInt, CREATE_ALWAYS, UInt, 0, Ptr, 0) if not hFile { MsgBox Can't open "%FileName%" for writing. return } TestString = This is a test string.`r`n <em>; When writing a file this way, use `r`n rather than `n to start a new line.</em>
<strong>DllCall</strong>("WriteFile", Ptr, hFile, Str, TestString, UInt, StrLen(TestString), UIntP, BytesActuallyWritten, Ptr, 0)
<strong>DllCall</strong>("CloseHandle", Ptr, hFile) <em>; Close the file.</em>

<em>; Now that the file was written, read its contents back into memory.</em>
GENERIC_READ = 0x80000000 <em>; Open the file for reading rather than writing.</em>
OPEN_EXISTING = 3 <em>; This mode indicates that the file to be opened must already exist.</em>
FILE_SHARE_READ = 0x1 <em>; This and the next are whether other processes can open the file while we have it open.</em>
FILE_SHARE_WRITE = 0x2 hFile := <strong>DllCall</strong>("CreateFile", Str, FileName, UInt, GENERIC_READ, UInt, FILE_SHARE_READ|FILE_SHARE_WRITE, Ptr, 0, UInt, OPEN_EXISTING, UInt, 0, Ptr, 0) if not hFile { MsgBox Can't open "%FileName%" for reading. return }
<em>; Make the variable empty for testing purposes, but ensure it retains sufficient capacity:</em>
BytesToRead := VarSetCapacity(TestString, StrLen(TestString))
<strong>DllCall</strong>("ReadFile", Ptr, hFile, Str, TestString, UInt, BytesToRead, UIntP, BytesActuallyRead, Ptr, 0)
<strong>DllCall</strong>("CloseHandle", Ptr, hFile) <em>; Close the file.</em>
MsgBox The following string was read from the file: %TestString%</pre>

<pre class="NoIndent"><a name="HideCursor"></a><em>; 示例: Hides the mouse cursor when you press Win+C. To later show the cursor, press Win+C again. ; This script is from <a href="http://www.autohotkey.com/forum/topic6107.html">www.autohotkey.com/forum/topic6107.html</a></em>

OnExit, ShowCursor <em>; Ensure the cursor is made visible when the script exits.</em>
return ShowCursor: SystemCursor("On") ExitApp #c::SystemCursor("Toggle") <em>; Win+C hotkey to toggle the cursor on and off.</em>

SystemCursor(OnOff=1) <em>; INIT = "I","Init"; OFF = 0,"Off"; TOGGLE = -1,"T","Toggle"; ON = others</em>
{ static AndMask, XorMask, $, h_cursor ,c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13 <em>; system cursors</em>
 , b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13 <em>; blank cursors</em>
 , h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11,h12,h13 <em>; handles of default cursors</em>
 if (OnOff = "Init" or OnOff = "I" or $ = "") <em>; init when requested or at first call</em>
 { $ = h <em>; active default cursors</em>
 VarSetCapacity( h_cursor,4444, 1 ) VarSetCapacity( AndMask, 32*4, 0xFF ) VarSetCapacity( XorMask, 32*4, 0 ) system_cursors = 32512,32513,32514,32515,32516,32642,32643,32644,32645,32646,32648,32649,32650 StringSplit c, system_cursors, `, Loop %c0% { h_cursor := DllCall( "LoadCursor", "Ptr",0, "Ptr",c%A_Index% ) h%A_Index% := DllCall( "CopyImage", "Ptr",h_cursor, "UInt",2, "Int",0, "Int",0, "UInt",0 ) b%A_Index% := DllCall( "CreateCursor", "Ptr",0, "Int",0, "Int",0 , "Int",32, "Int",32, "Ptr",&amp;AndMask, "Ptr",&amp;XorMask ) } } if (OnOff = 0 or OnOff = "Off" or $ = "h" and (OnOff &lt; 0 or OnOff = "Toggle" or OnOff = "T")) $ = b <em>; use blank cursors</em>
 else $ = h <em>; use the saved cursors</em>

 Loop %c0% { h_cursor := DllCall( "CopyImage", "Ptr",%$%%A_Index%, "UInt",2, "Int",0, "Int",0, "UInt",0 ) DllCall( "SetSystemCursor", "Ptr",h_cursor, "UInt",c%A_Index% ) } }</pre>

<pre class="NoIndent" id="ExStruct"><em>; Structure Example: Pass the address of a RECT structure to GetWindowRect(), which sets the structure's ; members to the positions of the left, top, right, and bottom sides of a window (relative to the screen).</em>

Run Notepad WinWait Untitled - Notepad <em>; This also sets the "<a href="../LastFoundWindow.htm">last found window</a>" for use with WinExist() below.</em>
VarSetCapacity(Rect, 16) <em>; A RECT is a struct consisting of four 32-bit integers (i.e. 4*4=16).</em>
<strong>DllCall</strong>("GetWindowRect", Ptr, WinExist(), Ptr, &amp;Rect) <em>; WinExist() returns an HWND.</em>
MsgBox % "Left " . <a href="../Functions.htm#NumGet">NumGet</a>(Rect, 0, "Int") . " Top " . NumGet(Rect, 4, "Int") . " Right " . NumGet(Rect, 8, "Int") . " Bottom " . NumGet(Rect, 12, "Int")</pre>

<pre class="NoIndent"><em>; Structure Example: Pass to FillRect() the address of a RECT structure that indicates a part of the ; screen to temporarily paint red.</em>

VarSetCapacity(Rect, 16, 0) <em>; Set capacity to hold four 4-byte integers and initialize them all to zero.</em>
<a href="../Functions.htm#NumPut">NumPut</a>(A_ScreenWidth//2, Rect, 8, "Int") <em>; The third integer in the structure is "rect.right".</em>
NumPut(A_ScreenHeight//2, Rect, 12, "Int") <em>; The fourth integer in the structure is "rect.bottom".</em>
hDC := <strong>DllCall</strong>("GetDC", "Ptr", 0, "Int") <em>; Pass zero to get the desktop's device context.</em>
hBrush := <strong>DllCall</strong>("CreateSolidBrush", "UInt", 0x0000FF) <em>; Create a red brush (0x0000FF is in BGR format).</em>
<strong>DllCall</strong>("FillRect", "Ptr", hDC, "Ptr", &amp;Rect, "Ptr", hBrush) <em>; Fill the specified rectangle using the brush above.</em>
<strong>DllCall</strong>("ReleaseDC", "Ptr", 0, "Ptr", hDC) <em>; Clean-up.</em>
<strong>DllCall</strong>("DeleteObject", "Ptr", hBrush) <em>; Clean-up.</em></pre>

<pre class="NoIndent"><em>; Structure Example: Change the system's clock to the specified date and time. Use caution when ; changing to a date in the future as it may cause scheduled tasks to run prematurely!</em>

SetSystemTime("20051008142211") <em>; Pass it a <a href="FileSetTime.htm#YYYYMMDD">timestamp</a> (local, not UTC).</em>

SetSystemTime(YYYYMMDDHHMISS)
<em>; Sets the system clock to the specified date and time. ; Caller must ensure that the incoming parameter is a valid date-time stamp ; (local time, not UTC). Returns non-zero upon success and zero otherwise.</em>
{ <em>; Convert the parameter from local time to UTC for use with SetSystemTime().</em>
 UTC_Delta -= A_NowUTC, Seconds <em>; Seconds is more accurate due to rounding issue.</em>
 UTC_Delta := Round(-UTC_Delta/60) <em>; Round to nearest minute to ensure accuracy.</em>
 YYYYMMDDHHMISS += UTC_Delta, Minutes <em>; Apply offset to convert to UTC.</em>

 VarSetCapacity(SystemTime, 16, 0) <em>; This struct consists of 8 UShorts (i.e. 8*2=16).</em>

 StringLeft, Int, YYYYMMDDHHMISS, 4 <em>; YYYY (year)</em>
 <a href="../Functions.htm#NumPut">NumPut</a>(Int, SystemTime, 0, "UShort") StringMid, Int, YYYYMMDDHHMISS, 5, 2 <em>; MM (month of year, 1-12)</em>
 NumPut(Int, SystemTime, 2, "UShort") StringMid, Int, YYYYMMDDHHMISS, 7, 2 <em>; DD (day of month)</em>
 NumPut(Int, SystemTime, 6, "UShort") StringMid, Int, YYYYMMDDHHMISS, 9, 2 <em>; HH (hour in 24-hour time)</em>
 NumPut(Int, SystemTime, 8, "UShort") StringMid, Int, YYYYMMDDHHMISS, 11, 2 <em>; MI (minute)</em>
 NumPut(Int, SystemTime, 10, "UShort") StringMid, Int, YYYYMMDDHHMISS, 13, 2 <em>; SS (second)</em>
 NumPut(Int, SystemTime, 12, "UShort") return <strong>DllCall</strong>("SetSystemTime", Ptr, &amp;SystemTime) }</pre>

<pre class="NoIndent"><em>/* <strong>More Structure Examples:</strong>

1) See the <a href="../scripts/WinLIRC.htm">WinLIRC client script</a> for a demonstration of how to use DllCall() to make a network connection to a TCP/IP server and receive data from it. 2) The operating system offers standard dialog boxes that prompt the user to pick a font and/or color, or an icon. These dialogs use structures and are demonstrated at <a href="http://www.autohotkey.com/forum/topic17230.html">www.autohotkey.com/forum/topic17230.html</a>. */</em></pre>

</body>
</html>
